/*
 * @Descripttion: 路径匹配过滤器
 * @version: 1.0.0
 * @Author: lfzxs@qq.com
 * @Date: 2023-05-09 14:56:49
 * @LastEditors: lfzxs@qq.com
 * @LastEditTime: 2023-05-11 15:35:00
 */
package middleware

import (
	"fmt"

	"gitee.com/g_boot/webkit/pathmatch"
	"github.com/gogf/gf/v2/net/ghttp"
	"golang.org/x/exp/slog"
)

type (
	matchMiddleware struct {
		BaseMiddleware
		// 日志类
		logger slog.Logger
		// 名称
		Name string
		// 是否可用
		Enable bool
		// 排除的路径
		ExcludePath []string

		Middleware ghttp.HandlerFunc
	}

	MatchOption func(mm *matchMiddleware)
)

func NewMatchMiddleware(name string, middleware ghttp.HandlerFunc, options ...MatchOption) *matchMiddleware {
	result := &matchMiddleware{
		Name:       name,
		Middleware: middleware,
		Enable:     true,
	}

	result.logger = *slog.Default()

	for _, option := range options {
		option(result)
	}

	return result
}

func WithEnanle(enable bool) MatchOption {
	return func(mm *matchMiddleware) {
		mm.Enable = enable
	}
}

// 设置忽略路径
func WithExcludePath(excludePath []string) MatchOption {
	return func(mm *matchMiddleware) {
		mm.ExcludePath = excludePath
	}
}

func WithLogger(logger slog.Logger) MatchOption {
	return func(mm *matchMiddleware) {
		mm.logger = logger
	}
}

func (s *matchMiddleware) matchExcludePath(path string) (match bool, pattern string) {
	match = false
	pattern = ""
	for i := 0; i < len(s.ExcludePath); i++ {
		patternStr := s.ExcludePath[i]
		matched, err := pathmatch.Match(patternStr, path)
		if err != nil {
			s.logger.Error("匹配异常"+err.Error(), slog.String("err", err.Error()))
			continue
		}

		s.logger.Debug(fmt.Sprintf("匹配结果(%t):pattern:%s,path:%s", matched, patternStr, path), slog.String("pattern", patternStr), slog.String("path", path))
		if matched {
			match = matched
			pattern = patternStr
			break
		}
	}
	return
}

func (s *matchMiddleware) middlewareEnable(path string) (result bool) {
	result = false
	if !s.Enable {
		s.logger.Debug(s.Name + "禁用中间件")
		return
	}

	if s.Middleware == nil {
		s.logger.Debug(s.Name + "包装中间件为空")
		return
	}

	exclude, _ := s.matchExcludePath(path)

	if exclude {
		s.logger.Debug(fmt.Sprintf("%s 路径(%s)被排除", s.Name, path), slog.String("name", s.Name), slog.String("path", path))
		return
	}

	result = true

	return
}

func (s *matchMiddleware) Handle(r *ghttp.Request) {

	path := r.URL.Path

	if s.middlewareEnable(path) {
		s.Middleware(r)
	} else {
		r.Middleware.Next()
	}

}
